<?php
class ProductApi {

    static $data_now;

    private $db = null;
    private $soap;
    static  $_soap;
    private $error;
    static public $remoteId;

    const MAX_SALER_ID = 987654;

    public function __construct(PDO $db)
    {
        $this->db = $db;
        $this->soap = self::soap();
    }

    public function __destruct()
    {
        $this->soap = null;
        $this->db = null;
    }
    /**
     * 计算数组差集的自定义函数
     *  使用方法：
     *      array_diff_uassoc($arr_new, $arr_old, array($this, '_c'));
     *      在类中使用时第三个参数（回调函数）必须是数组形式！
     *
     * @param $a
     * @param $b
     * @return int
     */
    private function _c($a, $b) {
        if($a===$b) return 0;
        return ($a > $b)? 1:-1;
    }
    /**
     * 向终端写入数据
     *
     * @param string $title 产品名称
     * @param string $salerid 资源方6位数账号
     * @param int $mode 操作模式0写入1更新
     * @param string $src_title 所属产品名称
     * @param string $dlTxt 延迟验证
     * @return mixed
     */
//    protected function _Write2Remote($title,$salerid,$mode=0,$src_title='', $dlTxt=NULL) {
//        $title .= !empty($src_title) ? $src_title:'';
//        if($mode==1) {
//            var_dump($title);
//            var_dump($salerid);
//            return $this->soap->Terminal_CFG_Update($title,$salerid,$dlTxt);
//        }
//        //echo  $salerid;
////        echo "$title,$salerid,$dlTxt";
//        $res = $this->soap->Terminal_CFG($title,$salerid,$dlTxt);
//        if(strpos($res,'|')!==false) {
//            $t_no = explode('|', $res);
//            return  array(
//                'status' => 'ok',
//                'msg'  => '生成终端号成功',
//                'body' => $t_no[1]
//            );
//        }
//        return array(
//            'status' => 'fail',
//            'msg'  => $res,
//            'body' => ''
//        );
//    }
    /**
     * 根据相应字段验证产品是否已经存在
     *
     * @param string $pro 验证字段的值
     * @param string $colmn 字段名
     * @param array $other 字段名
     * @return mixed
     */
    protected function _chkProExist($pro, $colmn, $other=array())
    {
        $str = "SELECT COUNT(*) AS c FROM uu_land WHERE `{$colmn}`='{$pro}'";
        if(!empty($other) && is_array($other)) {
            $str .= " AND " . self::getValues($other);
        }

        $stmt = $this->db->prepare($str);
        $stmt->execute();
        return $stmt->fetchColumn(0);
    }

    /**
     * 获取产品总表ID
     *
     * @param $id 门票ID
     * @return mixed
     */
    protected function _getPid($id) {
        $sql = "SELECT pid FROM uu_jq_ticket WHERE id={$id} LIMIT 1";
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        return $stmt->fetchColumn(0);
    }

    /**
     * 验证产品是新增还是更新。若为更新，放回lid和tid。
     *
     * @param $account
     * @param $remoteid
     * @return int|mixed
     */
    public function ChkUpdateOrInsert($account, $remoteid)
    {
        $sql = "SELECT pid FROM get_Product_Fromt_Lib"
            ." WHERE account=$account AND remoteid='$remoteid' LIMIT 1";
        $stmt = $this->db->prepare($sql);
        $stmt ->execute();
        $pid = $stmt ->fetchColumn(0);
        if (!$pid) {
            return false;
        }
        $sqlProduct = "SELECT id as lf_id,tid,lid FROM uu_land_f WHERE pid=$pid LIMIT 1";
        $stmt = $this->db->prepare($sqlProduct);
        $stmt ->execute();
        return $stmt ->fetch(PDO::FETCH_ASSOC);
    }

    /**
     *
     * 添加产品
     *
     * @param array $params 字段名=>值（参考uu_land表）
     * @param null $dltxt
     * @return array
     */
    public function AddProduct($params, $dltxt=NULL)
    {
        //unique check
        $sql_uni = "SELECT id FROM uu_land WHERE title=? AND apply_did=? LIMIT 1";
        $stmt    = $this->db->prepare($sql_uni);
        $stmt->execute(array($params['title'], $params['apply_did']));
        if ($last_id = $stmt->fetchColumn(0)) {
            return array(
                'status'=>'ok',
                'msg'=>'该供应商已发布该景区',
                'lastid'=>$last_id
            );
        }
        $memParams = array(
            'dname'=>$params['title'],
            'dtype'=>2,//直接供应方
            'password'=>'b81b84c7961ac41a9e619458511a98d9',//md5(md5('uu654321'))
        );
        //生成直接供应商
        $reg_res = $this->register($memParams, array());
        if( $reg_res===false ) {
            return 1;
        }
        else {
            if(strlen($params['salerid'])>6 || $params['salerid']>=self::MAX_SALER_ID) {
                return array('errcode'=>1001,'msg'=>'添加失败，商户ID超出长度！');
            }
            $params['salerid'] = $reg_res['account'];
            //建立直接供应商与供应商关系
            $rel_res = $this->createRelationship($params['apply_did'],
                $reg_res['mid'],1,1);
            if ( $rel_res===false ){
                return 2;
            }
        }
        //检测是否存在相同的产品名称，若存在则将产品名称重命名
        $strChkTitle = "SELECT COUNT(*) AS c FROM uu_land WHERE title='{$params['title']}'";
        $stmt = $this->db->prepare($strChkTitle);
        $stmt->execute();
        $count = $stmt->fetchColumn(0);
        $src_title = $count>0? '_' . ($count+1):'';

//        $res = self::_Write2Remote($params['title'], $params['salerid'],0,
//            $src_title,$dltxt);

        //获取终端号
        $max_terminal_log = '/var/www/html/new/d/common/max_terminal_id.txt';

        $max_terminal = (int)HandleLastData($max_terminal_log);
        $max_terminal = $max_terminal + 1;

        $params['terminal']         = $max_terminal;
        $params['terminal_type']    = 1;
        $params['status']           = 1;
        $params['addtime']          = date('Y-m-d H:i:s');
        $stradd = self::sqlInsert('uu_land', $params);
        try {
            $this->db->exec($stradd);
            HandleLastData($max_terminal_log, 1, $max_terminal);
            return array(
                'status'=>'ok',
                'msg'=>'添加成功',
                'lastid'=>$this->db->lastInsertId()
            );
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($stradd);
            return false;
        }

    }

    /**
     * 更新景区信息（uu_land表）
     *
     * @param array $params 字段名=>值
     * @param integer $id   表ID
     * @param string $dlTxt 延迟验证
     * @return array
     */
    public function UpdateScenery(Array $params,$id, $dlTxt=NULL) {
        //echo 'abc';
        //TODO-CGP 验证该产品名称是否已经存在
        if(!self::_chkProExist($id, 'id')) {
            return array('errcode'=>1004,'msg'=>'修改的数据不存在，请刷新页面后重试');
        }
        $clns = implode(',', array_keys($params));
        $str = "SELECT {$clns},salerid FROM uu_land WHERE id={$id} LIMIT 1";
        //echo $str;
        $stmt = $this->db->prepare($str);
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $diff_array = array_diff_uassoc($params, $result,array($this,'_c'));//比较差集
        if(!count($diff_array)) {
            return array('errcode'=>1000,'msg'=>'更新成功','lastid'=>$id);
        }
        $str = "UPDATE uu_land SET " . $this->getValues($diff_array). " WHERE id={$id} LIMIT 1";
        //echo $str;
        //return;
        //更新终端
//        if(isset($diff_array['title']) || $dlTxt!==NULL){
//            $r2 = $this->_Write2Remote($params['title'], $result[0]['salerid'], 1,'',$dlTxt);
//            if($r2!==100) {
//                return array('errcode'=>1100,'msg'=>'更新终端名称失败,请核对产品名称后重新保存。错误代码：'.$r2);
//            }
//        }
        try {
            $this->db->exec($str);
            return array('errcode'=>1000,'msg'=>'更新成功','lastid'=>$id);
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($str);
            return false;
        }
    }

    /**
     * 添加景区门票
     *
     * @param array $data 门票表(uu_jq_ticket)字段名=>值
     * @param int $tid 大于0为更新，门票ID
     * @return array
     */
    public function SaveTicket($data, $tid=0) {
        //TODO-done:验证景区是否已经存在，不存在的禁止添加
        if(! self::_chkProExist($data['landid'], 'id','uu_land')) {
            return array('status'=>'fail','msg'=>'景区不存在，添加失败');
        }
        if ($tid) {
            $strBefore = <<<SQL
SELECT `id`, `landid`,`pid`, `title`, `tprice`, `uprice`, `px`,`status`, `pay`,
`notes`,`getaddr`, `ifs`, `delaydays`, `storage`, `s_limit_up`, `s_limit_low`,
`buy_limit_up`, `buy_limit_low`, `open_time`, `end_time`, `apply_did`,
`modify_op`, `order_limit`, `order_end`, `delaytype`,`sync_id`,`sync_status`,
`ddays` FROM uu_jq_ticket WHERE title='{$data['title']}' LIMIT 1
SQL;
            $stmt = $this->db->prepare($strBefore);
            $stmt->execute();
            $dataBefore = $stmt->fetch(PDO::FETCH_ASSOC);
            $datas = array_diff_uassoc($data, $dataBefore, array($this,'_c'));
            $str = self::sqlUpdate('uu_jq_ticket', $datas, "title='{$data['title']}' LIMIT 1");
        }
        else {
            $str = self::sqlInsert('uu_jq_ticket', $data);
        }
        try {
//            echo $str;exit;return;
            $this->db->exec($str);
            if (!$tid) {
                $lastid = $this->db->lastInsertId();
                $pid = self::_getPid($lastid);
            }
            else {
                $lastid = $dataBefore['id'];
                $pid    = $dataBefore['pid'];
            }
            return array(
                'status' => 'ok',
                'lastid' => $lastid,
                'pid'    => $pid,
                'landid' => $data['landid']
            );
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($str);
            return false;
        }
    }

    /**
     * 产品扩展表（uu_land_f）新增OR更新
     *
     * @param $params
     * @param int $id 表ID，大于0为更新
     * @param bool $debug 是否调试
     * @return int
     */
    public function ProductExt($params, $id=0) {
        if($id>0) {
            $str_s = "SELECT * FROM uu_land_f WHERE id={$id}";
            $stmt = $this->db->prepare($str_s);
            $stmt->execute();
            $row = $stmt ->fetchAll();
            $cr = array_diff_uassoc($params , $row, array($this, '_c'));

            if(count($cr)) {
                $str = self::sqlUpdate('uu_land_f', $cr,  " WHERE id={$id} LIMIT 1");
                try {
                    $this->db->exec($str);
                    return true;
                } catch(PDOException $e) {
                    $this->error = $e->getMessage();
                    $this->debug($str);
                    return false;
                }

            }
        }
        else {
            $str = self::sqlInsert('uu_land_f', $params);
            try {
                $this->db->exec($str);
                return true;
            } catch(PDOException $e) {
                $this->error = $e->getMessage();
                $this->debug($str);
                return false;
            }
        }
    }


    /**
     * 产品价格配置
     *   接口说明：
     *        1).供应商产品动态价格插入或修改(商品总表ID，开始日期，结束日期，
     *              供应价，零售价，类型(0平日1周末2特殊)，记录模式[0插入1修改2修改]，
     *              记录ID[修改状态下需要，记录模式为2时代表映射ID]，价格说明，日库存)
     *        2).In_Dynamic_Price_Merge($pid, $startdate='', $enddate='',
     *                  $g_price=0, $l_price=0, $ptype=0, $mode=0,
     *               $rid=0, $memo='', $ondays=''，$storage='')
     *  update:
     *      1).2013年9月29日11:38:01——添加“日库存”字段
     *      2).2013年10月8日15:35:08——去除获取分销id操作，
     *
     * @param $pid 商品总表ID
     * @param string $startdate 开始日期
     * @param string $enddate 结束日期
     * @param int $g_price 供应价
     * @param int $l_price 零售价
     * @param int $ptype 类型(0平日1周末2特殊)
     * @param int $rid 记录ID[修改状态下需要]
     * @param string $memo 价格说明
     * @param string $ondays 星期
     * @param string $storage 日库存 -1不限量0售罄
     * @return mixed
     */
    public function AddPrice($pid, $startdate='', $enddate='',
                             $g_price=0, $l_price=0, $ptype=0, $rid=0, $memo='', $ondays='', $storage=-1)
    {
        $mode = $rid > 0 ? 1 : 0;
        $res = $this->soap->In_Dynamic_Price_Merge($pid, $startdate, $enddate,
            $g_price, $l_price, $ptype, $mode, $rid, $memo, $ondays, $storage);
        return $res;
    }

    /**
     * 产品上下架。下架需要将票类下架
     *
     * @param $lid
     * @param $state
     */
    public function SetProductState($lid, $state)
    {
        $sql = "SELECT title FROM uu_land WHERE id=$lid LIMIT 1";
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        $title = $stmt->fetchColumn(0);
        if (!$title) {
            self::writeLog(self::now() . "ID:{$lid}被设置为{$state}失败！数据不存在", 'set_uu_land.err');
            return false;
        }
        $sql = "UPDATE uu_land SET status=$state WHERE id=$lid LIMIT 1";
        $this->db->exec($sql);
        self::writeLog(self::now() . "{$title}(ID:{$lid})被设置为{$state}", 'set_uu_land.log');
        if ($state==2) {
            $this->SetTicketState($lid, 2, 2);
        }
    }

    /**
     * 票类下架
     *
     * @param $id
     * @param $state
     * @param int $by
     * @return array|int
     */
    public function SetTicketState($id, $state, $by=1)
    {
        $where = $by==1 ? "id=$id LIMIT 1" : "contact_id=$id";
        $stmt = $this->db->prepare($sql_before);
        $stmt->execute();
        $pid = array();
        if ($by==2) {
            $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
            foreach ($products as $product) {
                $pid[] = $product['id'];
                self::writeLog(self::now() . "{$product['p_name']}(PID:{$product['id']})的设置为[{$state}]", 'set_uu_products.log');
            }
        }
        elseif ($by==1) {
            $pid[] = $id;
            $product = $stmt->fetch(PDO::FETCH_ASSOC);
            self::writeLog(self::now() . "{$product['p_name']}(PID:{$product['id']})的设置为[{$state}]", 'set_uu_products.log');
        }
        if (count($pid)) {
            $sql = "UPDATE uu_products SET apply_limit=$state,p_status=0,verify_time=now() WHERE $where";
            $this->db->exec($sql);
            return $pid;
        }
        self::writeLog(self::now() . "票类数据不存在,SQL={$sql_before}", 'set_uu_products.err');
        return false;

    }
    /**
     * 验证产品标志位填入数据库
     *
     * @param $account
     * @param $remoteid
     * @return int|mixed
     */
    public function InsertProduct_Fromt($account,$pid,$remoteid)
    {
        $sql = "insert into get_Product_Fromt_Lib (account,pid,remoteid,rectime)  values ($account,$pid,$remoteid,now())";
        $stmt = $this->db->prepare($sql);
        $stmt ->execute();
        return $stmt ->rowCount();
    }
    private function generateSalerId()
    {
        $max = 861212;//864364
        $min = 617679;
        $str1 = "SELECT max(salerid) as s1 from uu_land WHERE salerid>$min AND salerid<$max";
        $stmt = $this->db->prepare($str1);
        $stmt->execute();
        $s1  = $stmt->fetchColumn(0);
        if (!$s1) {
            return $min + 1;
        }
        $str = <<<SQL
        SELECT MIN(account)+1 as passport FROM pft_member WHERE dtype=2
        AND account > $s1 AND account < $max
SQL;
        $stmt = $this->db->prepare($str);
        $stmt->execute();
        $p1 = $stmt->fetchColumn(0);
        if (!$p1) {
            return $s1 + 1;
        }

        $str_chk = "SELECT id FROM pft_member WHERE account=$p1 LIMIT 1";
        $stmt = $this->db->prepare($str_chk);
        $stmt->execute();
        if ($stmt->fetchColumn(0)>0) {
            $str = <<<SQL
        SELECT MAX(account)+1 as passport FROM pft_member WHERE dtype=2
        AND account BETWEEN $min AND 999999 AND dtype=2
SQL;
            $stmt = $this->db->prepare($str);
            $stmt->execute();
            $p1 = $stmt->fetchColumn(0);
        }
        return $p1;
    }
    /**
     * 会员注册
     *
     * @param array $mainData 会员主表数据（字段参考表结构）
     * @param array $extData  会员扩展表数据（字段参考表结构）
     * @return array|int
     * @throws \InvalidArgumentException
     */
    public function register($mainData, $extData=array())
    {
        $mainData['account']    = self::generateSalerId();
        $mainData['headphoto']  = 'images/touxiang.png';//默认头像
        $mainData['creattime']  = date('Y-m-d H:i:s');
        $str = self::sqlInsert('pft_member', $mainData);
        try {
            $this->db->exec($str);
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($str);
            return false;
        }


        $last_insertid       = $this->db->lastInsertId();
        $extData['fid']      = $last_insertid;
        $extData['bsn_les']  = 'images/other/noimg.jpg';
        $extData['opt_les']  = 'images/other/noimg.jpg';
        $extData['auth_les'] = 'images/other/noimg.jpg';
        $extData['id_card']  = 'images/other/noimg.jpg';
        $str = self::sqlInsert('pft_member_extinfo', $extData);
        try {
            $this->db->exec($str);
            return array(
                'status'    =>'ok',
                'mid'       => $last_insertid,
                'account'   =>$mainData['account'],
            );
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($str);
            return false;
        }

    }

    public function createRelationship($parent_id, $son_id, $son_id_type=0,
                                       $ship_type=0)
    {
        $son_type_list = array('分销商','资源方','员工','供应商');
        if(!is_numeric($parent_id) || !$parent_id) {
            throw new \InvalidArgumentException('$parent_id必须为大于0的数字');
        }
        $str = <<< SQL
        INSERT INTO pft_member_relationship(parent_id,son_id,son_id_type,
        ship_type,rectime) 
        VALUES({$parent_id},{$son_id},{$son_id_type},{$ship_type},now())
SQL;
        try {
            $this->db->exec($str);
            $msg = $son_type_list[$son_id_type].'添加成功';
            return array(
                'status'=>'ok',
                'msg'   => $msg,
                'body'  => $this->db->lastInsertId(),
            );
        } catch(PDOException $e) {
            $this->error = $e->getMessage();
            $this->debug($str);
            return false;
        }

    }

    public static function now()
    {
        if (!is_null(self::$data_now)) {
            return self::$data_now;
        }
        self::$data_now = date('Y-m-d H:i:s');
        return self::$data_now;
    }

    /**
     * @param $account
     * @param $verifyCode
     * @return mixed bool|$apply_id
     */
    public function Auth($account, $verifyCode)
    {
        $sqlPwd = "select id,password FROM pft_member WHERE account='{$account}' LIMIT 1";
        $stmt = $this->db->prepare($sqlPwd);
        $stmt->execute();
        $row  = $stmt->fetch(PDO::FETCH_ASSOC);
        $apply_did  = $row['id'];
//        $myPwd      = $row['password'];
//        echo $apply_did . '---' .$myPwd;exit;
        $realVerifyCode = md5('pft'.substr($row['password'], 0, 16) . '12301');
//        echo $realVerifyCode;//69d5c5a09b6712ee07f1953cd7c6b38c
        //a6b167ecb9c5fa3b6327969681aa6f37
        //$realVerifyCode = md5('pft'.substr($password, 0, 16) . '12301');
        if ( $realVerifyCode!=$verifyCode ) {
            return false;
        }
        return $apply_did;
    }

    /**
     * 获得sql语句使用的字段名和值
     *
     * @param $params
     * @return string
     */
    protected function getValues($params) {
        $str = '';
        foreach($params as $key=>$val) {
            if($key=='order_end' && $val==''){
                $str .= "`{$key}`=NULL,";
            }else{
                $str .= "`{$key}`='{$val}',";
            }
        }
        return rtrim($str,',');
    }

    private function debug($sql='') {
        $error = array("Error" => $this->error);
        if(!empty($sql))
            $error["SQL Statement"] = $sql;

        $backtrace = debug_backtrace();
        if(!empty($backtrace)) {
            foreach($backtrace as $info) {
                if($info["file"] != __FILE__)
                    $error["Backtrace"] = $info["file"] . " at line " . $info["line"];
            }
        }
        $msg = "";
        $msg .= "SQL Error\n" . str_repeat("-", 50);
        foreach($error as $key => $val) {
            $msg .= "\n\n$key:\n$val";
        }
        self::writeLog(self::now() . '|' . $msg, 'sql_error.err');
    }

    static function sqlInsert($tbname,$row)
    {
        $sqlInsert='insert '.$tbname.' set ';
        $sqlVal='';
        foreach($row as $k =>$v)
        {
            $sqlVal.= add_special_char($k).'= \''.addslashes($v).'\',';
        }
        $sqlInsert.=substr($sqlVal,0,-1);
        return $sqlInsert;
    }

    static function sqlUpdate($tbname, $row, $where) {
        $sqlud='';
        foreach ( $row as $key => $value ) {
            $sqlud.=add_special_char($key).'=\''.addslashes($value).'\',';
        }
        return "UPDATE `".$tbname."` SET " . substr ( $sqlud, 0, - 1 )." WHERE " . $where;
    }

    static public function writeLog($word, $filename) {
        $path ='/var/www/html/new/d/logs/api/data_import';
        if (!is_dir($path)) {
            mkdirs($path);
        }
        $file  = $path . DIRECTORY_SEPARATOR . $filename.'_'.date('d').'.log';
        $fp = fopen($file,"a");
        flock($fp, LOCK_EX) ;
        fwrite($fp,"\n".$word);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    static public function soap()
    {
        if (is_null(self::$_soap)) {
            self::$_soap = new SoapClient(null,array(
                    "location" => "http://localhost/open/openService/pft_insideMX.php",
                    "uri" => "www.16u.com?ac_16u=16ucom|pw_16u=c33367701511b4f6020ec61ded352059|auth_16u=true")
            );
        }
        return self::$_soap;
    }

    static public function Response($code, $array=null)
    {
        $json = '{"code":' . $code .',"pid":' . self::$remoteId . '}';
        if (is_array($array)) {
            exit(json_encode($array));
        }
        exit($json);
    }
}

